#include "xict_ui_core/imageglitem.h"
#include <QMatrix4x4>
#include <QOpenGLFramebufferObjectFormat>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QOpenGLVertexArrayObject>
#include <QVector3D>

// 数据上下文
struct Context {
    QImage image;
};

// 顶点矩阵 Vertex matrix
static const GLfloat vertexVertices[] = {
    -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
};

// 纹理矩阵 Texture matrix
static const GLfloat textureVertices[] = {
    0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
};

// OpenGL 渲染
class ImageGLItemRenderer : public QQuickFramebufferObject::Renderer,
                            protected QOpenGLFunctions {
public:
    ImageGLItemRenderer() : texture(QOpenGLTexture::Target2D) {
        // 初始化 OpenGL 上下文
        Initialize();
        texture.create();
    }
    ~ImageGLItemRenderer() {
        texture.destroy();
    }
    void Initialize() {
        initializeOpenGLFunctions();
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        if (!shaderProgram.addCacheableShaderFromSourceFile(
                QOpenGLShader::Vertex, ":/vertexshader.vert")) {
            qWarning() << QString("[ERROR] Vertex shader: %1")
                              .arg(shaderProgram.log());
        }
        if (!shaderProgram.addCacheableShaderFromSourceFile(
                QOpenGLShader::Fragment, ":/fragmentshader.frag")) {
            qWarning() << QString("[ERROR] Vertex shader: %1")
                              .arg(shaderProgram.log());
        }

        shaderProgram.bindAttributeLocation("qt_Vertex", indexVvertex);
        shaderProgram.bindAttributeLocation("qt_MultiTexCoord0", indexTexture);

        if (!shaderProgram.link()) {
            qWarning() << QString("[ERROR] ShaderProgram link: %1")
                              .arg(shaderProgram.log());
        }

        sampler2D = shaderProgram.uniformLocation("qt_Texture0");
        projectionMatrix =
            shaderProgram.uniformLocation("qt_ModelViewProjectionMatrix");
    }
    virtual QOpenGLFramebufferObject*
    createFramebufferObject(const QSize& size) override {
        QOpenGLFramebufferObjectFormat format;
        format.setSamples(4);
        return new QOpenGLFramebufferObject(size, format);
    }

    // 渲染
    virtual void render() override {
        glClear(GL_DEPTH_BUFFER_BIT);

        constexpr const float angle = 0.0f;
        constexpr const float scale = 1.0f;
        QMatrix4x4 modelview;
        modelview.rotate(angle, 0.0f, 1.0f, 0.0f);   // y
        modelview.rotate(angle, 1.0f, 0.0f, 0.0f);   // x
        modelview.rotate(angle, 0.0f, 0.0f, 1.0f);   // z
        modelview.scale(scale);
        modelview.translate(0.0f, 0.0f, 0.0f);

        if (!shaderProgram.bind()) {
            qWarning() << QString("[ERROR] ShaderProgram bind: %1")
                              .arg(shaderProgram.log());
        }

        shaderProgram.setUniformValue(sampler2D, 0);
        shaderProgram.setUniformValue(projectionMatrix, modelview);

        shaderProgram.setAttributeArray(indexVvertex, vertexVertices, 2, 0);
        shaderProgram.setAttributeArray(indexTexture, textureVertices, 2, 0);

        shaderProgram.enableAttributeArray(indexVvertex);
        shaderProgram.enableAttributeArray(indexTexture);

        texture.bind();

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        shaderProgram.disableAttributeArray(indexVvertex);
        shaderProgram.disableAttributeArray(indexTexture);

        shaderProgram.release();
    }

    // 同步数据
    void synchronize(QQuickFramebufferObject* item) override {
        ImageGLItem* obj = static_cast<ImageGLItem*>(item);
        if (obj) {
            auto image = obj->context()->image;
            if (image.width() != texture.width() ||
                image.height() != texture.height()) {
                // 大小已改变 更新纹理
                textureResize(image.width(), image.height());
                texture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8,
                                image.constBits());
            } else {
                texture.setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8,
                                image.constBits());
            }
        }
    }
    // 重置纹理
    inline void textureResize(int width, int height) {
        texture.destroy();
        texture.create();
        texture.setMinMagFilters(QOpenGLTexture::Linear,
                                 QOpenGLTexture::Linear);
        texture.setSize(width, height);
        texture.setFormat(QOpenGLTexture::RGBA8_UNorm);
        texture.allocateStorage();
    }
    //
    QOpenGLShaderProgram shaderProgram;
    GLint sampler2D        = -1;
    GLint projectionMatrix = -1;
    QOpenGLTexture texture;
    //顶点&纹理索引
    GLuint indexVvertex = 0;
    GLuint indexTexture = 1;
};

ImageGLItem::ImageGLItem(QQuickItem* parent)
    : QQuickFramebufferObject(parent), m_ctx(new Context) {
    setMirrorVertically(true);
    settop_screen(false);
    setcut_num(1);
}

QQuickFramebufferObject::Renderer* ImageGLItem::createRenderer() const {
    return new ImageGLItemRenderer();
}

QSharedPointer<Context> ImageGLItem::context() {
    return m_ctx;
}

void ImageGLItem::paintImage(const QImage& image, int state) {
    if (m_cut_num > 1) {
        if (state == -1) {
            int sub_width = image.width() / m_cut_num;
            if (m_top_screen) {   //显示开机动画
                m_ctx->image =
                    image.copy((image.width() - 1920) / 2, 0, 1920, 1080);
            } else {
                m_ctx->image = image.copy(m_image_index * sub_width + 1, 1080,
                                          sub_width - 1, 1920);
            }
        } else {
            if (m_top_screen) {
                m_ctx->image = image.copy();
            } else if (state > 0) {
                int sub_width = image.width() / m_cut_num;
                m_ctx->image =
                    image.copy(m_image_index * sub_width + 10, 0,
                               sub_width - 10, image.height());   //显示实时图像
            } else {
                int sub_width = image.width() / 3;
                if (m_image_index > 0 && m_image_index < 4) {
                    m_ctx->image = image.copy(
                        (m_image_index - 1) * sub_width + 10, 0, sub_width - 10,
                        image.height());   //显示实时图像
                } else
                    m_ctx->image = QImage();
            }
        }
    } else {
        if (m_revolve) {
            QMatrix matrix;
            if (state == 1) {
                matrix.rotate(90.0);
            } else {
                matrix.rotate(-90.0);
            }
            QImage tmp_image = image.transformed(matrix);
            m_ctx->image     = tmp_image.copy();
        } else {
            m_ctx->image = image.copy();
        }
    }

    if (m_ctx->image.format() != QImage::Format_RGB888) {
        QImage temp  = m_ctx->image.convertToFormat(QImage::Format_RGB888);
        m_ctx->image = temp;
    }

    //    m_ctx->image =
    //    image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
    update();
}
